//
//  VideoActor.swift
//  SitPosition
//
//  Created by apple on 2019/2/8.
//  Copyright © 2019 apple. All rights reserved.
//

import Foundation
import AVFoundation
import CoreImage


/**
 * 视频采集管理器
 */
protocol VideoActorDelegate : class {
    
    // 用户拒绝了相机权限
    func videoActorNotGrantPermission() -> Void
    
    // 处理一帧数据
    func videoActorDidOutput(_ sampleBuffer: CMSampleBuffer) -> Void
}


class VideoActor : NSObject {
    
    // 渲染视图
    public class RenderView : UIView {
        
        var renderLayer: CALayer? = nil {
            willSet {
                if newValue == nil {
                    if let renderLayer_ = renderLayer {
                        renderLayer_.removeFromSuperlayer()
                    }
                }
            }
            didSet {
                if let renderLayer_ = renderLayer {
                    layer.addSublayer(renderLayer_)
                }
            }
        }
        
        override func layoutSubviews() {
            super.layoutSubviews()
            renderLayer?.frame = bounds
        }
    }
    
    // MARK: - Properties
    
    // 代理
    public weak var delegate: VideoActorDelegate? = nil
    
    // 视频渲染视图
    public let renderView: RenderView = RenderView()
    
    // 显示模式
    public var videoGravity: AVLayerVideoGravity = AVLayerVideoGravity.resizeAspect {
        didSet {
            guard cameraLayer != nil else { return }
            cameraLayer.videoGravity = videoGravity
        }
    }

    // 拍摄会话
    private var captureSession: AVCaptureSession? = nil
    private var captureDevice: AVCaptureDevice? = nil
    private let videoOutput: AVCaptureVideoDataOutput = AVCaptureVideoDataOutput()
    private var cameraLayer: AVCaptureVideoPreviewLayer!
    
    // MARK: - Object lifecycle
    deinit {
        stop()
    }
    
    // MARK: - Public Methods
    
    // 开始采集
    public func start() throws -> Void {
        guard captureSession == nil else {
            captureSession?.startRunning()
            return
        }
        
        // 检查设备类型
        let deviceType = UIDevice.current.userInterfaceIdiom
        guard deviceType == .phone || deviceType == .pad else {
            fatalError("ERROR: Invalid device")
        }
        
        // 检查摄像机的权限
        AVCaptureDevice.requestAccess(for: AVMediaType.video) { [weak self] (response) in
            DispatchQueue.main.async {
                if response {
                    self?._setupCamera()
                } else {
                    self?.delegate?.videoActorNotGrantPermission()
                }
            }
        }
    }
    
    // 停止采集
    public func stop() -> Void {
        if (captureSession?.isRunning ?? false) {
            captureSession?.stopRunning()
        }
    }
}

// MARK: - Private Methods

extension VideoActor {
    
    // 设置摄像头
    private func _setupCamera() {
        let deviceDiscovery = AVCaptureDevice.DiscoverySession(deviceTypes: [AVCaptureDevice.DeviceType.builtInWideAngleCamera], mediaType: AVMediaType.video, position: AVCaptureDevice.Position.front)
        if let device = deviceDiscovery.devices.last {
            captureDevice = device
            _beginSession()
        }
    }
    
    // 开启会话
    private func _beginSession() {
        guard let videoDevice = captureDevice else {
            return
        }
        let session: AVCaptureSession = AVCaptureSession()
        
        // 添加输入
        if let videoInput = try? AVCaptureDeviceInput(device: videoDevice) {
            if session.canAddInput(videoInput) {
                session.addInput(videoInput)
            }
        }
        
        // 添加输出
        videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "sample buffer"))
        if session.canAddOutput(videoOutput) {
            session.addOutput(videoOutput)
        }
        
        // 配置Session
        let deviceType = UIDevice.current.userInterfaceIdiom
        session.sessionPreset = .medium
        
        // 构造摄像头预览层
        cameraLayer = AVCaptureVideoPreviewLayer(session: session)
        cameraLayer.videoGravity = videoGravity
        cameraLayer.frame = renderView.bounds
        renderView.renderLayer = cameraLayer
        
        // 启动Session...
        captureSession = session
        session.startRunning()
    }
}

// MARK: - AVCaptureVideoDataOutputSampleBufferDelegate

extension VideoActor : AVCaptureVideoDataOutputSampleBufferDelegate {
    
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        // the final picture is here, we call the completion block
        delegate?.videoActorDidOutput(sampleBuffer)
    }
    
    func captureOutput(_ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        // dbgPrint("VideoActor: dropped one sample buffer")
    }
}

